package org.lora.core.configxml.impl;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.lora.core.configxml.IConfigXmlExplain;
import org.lora.core.configxml.entity.ConfigXmlEntity;
import org.lora.core.configxml.entity.MongoDBConfig;
import org.lora.core.configxml.entity.MyBatisConfig;
import org.lora.core.configxml.entity.WebSecurityConfig;
import org.lora.exception.XmlConfigException;
import org.lora.util.StringUtil;
import org.lora.util.ValidateUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * <p>
 * 类名:ConfigXmlExplainJDKImpl
 * </p>
 * 描述:<br>
 * 创建时间:2016年6月16日 下午11:40:54<br>
 * 
 * @author Bladnir@outlook.com<br>
 *         修改历史:<br>
 *         2016年06月16日 Bladnir 创建<br>
 */
public class ConfigXmlExplainJDKImpl implements IConfigXmlExplain {

	private static final String ENTRY_KEY = "key";

	private static final String ENTRY_VALUE = "value";

	public static void main(String[] args) {
		ConfigXmlExplainJDKImpl instance = new ConfigXmlExplainJDKImpl();
		try {
			instance.establishConfigXml("D:\\Middleware\\apache-tomcat-7.0.70-alpha\\webapps\\alpha\\WEB-INF\\config\\lora.xml");

			System.out.println("success");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.lora.core.configxml.IConfigXmlExplain#establishConfigXml(java.lang
	 * .String)
	 */
	@Override
	public ConfigXmlEntity establishConfigXml(String xmlFilePath) throws XmlConfigException {

		ConfigXmlEntity config = new ConfigXmlEntity();

		try {
			// 获取配置xml Document对象
			Document document = getConfigDocument(xmlFilePath);

			// 获取文档元素（这里是主元素）
			Element root = document.getDocumentElement();

			// 创建数据库配置
			// createDatabaseConfig(root, config);

			// 创建MyBatis配置
			createMybatisConfig(root, config);

			// 创建数据源配置
			createDataSourceConfig(root, config);

			// 创建Quartz配置
			createQuartzConfig(root, config);

			// MongoDB配置
			createMongoDBConfig(root, config);

			// WebSecurity配置
			createWebSecurityConfig(root, config);

			// 扫描根路径
			List<String> basePackNameList = new ArrayList<>();

			NodeList list = root.getElementsByTagName("basePackName");
			for (int i = 0; i < list.getLength(); i++) {
				Node node = list.item(i);
				if (node.getNodeType() != Node.ELEMENT_NODE) {
					continue;
				}
				basePackNameList.add(node.getAttributes().getNamedItem("name").getNodeValue());
			}

			if (ValidateUtil.isEmpty(basePackNameList)) {
				throw new XmlConfigException("XmlErr04", "EstablishConfigXml basePackNameList is empty");
			}

			config.setBasePackNameList(basePackNameList);
		} catch (ParserConfigurationException | SAXException | IOException | NoSuchFieldException | IllegalAccessException e) {
			throw new XmlConfigException(e);
		}

		return config;
	}

	/**
	 * 获取配置xml Document对象
	 * 
	 * @param xmlFilePath
	 * @return
	 * @throws XmlConfigException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	private Document getConfigDocument(String xmlFilePath) throws XmlConfigException, ParserConfigurationException, SAXException,
			IOException {
		if (StringUtil.isNull(xmlFilePath)) {
			throw new XmlConfigException("XmlErr01", "EstablishConfigXml xmlFilePath is null");
		}

		File xmlFile = new File(xmlFilePath);

		if (!xmlFile.exists()) {
			throw new XmlConfigException("XmlErr02", "EstablishConfigXml XML File is not exists xmlFilePath=[" + xmlFilePath + "]");
		}

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 可获取XML解析器
		DocumentBuilder builder = factory.newDocumentBuilder();// 获取文档生成器
		Document document = builder.parse(xmlFile);// 获取文档

		if (document == null) {
			throw new XmlConfigException("XmlErr03", "EstablishConfigXml build document fail xmlFilePath=[" + xmlFilePath + "]");
		}

		return document;
	}

	/**
	 * Quartz配置
	 * 
	 * @param root
	 * @param config
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	private void createQuartzConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException {

		List<Node> nodeList = this.getRealNodeList(root.getElementsByTagName("quartz"));
		if (ValidateUtil.isEmpty(nodeList)) {
			return;
		}

		Properties properties = new Properties();

		// 目前只有一个
		for (Node valueNode : nodeList) {
			if (valueNode.getNodeType() != Node.ELEMENT_NODE) {
				continue;
			}

			NodeList valueNodeList = valueNode.getChildNodes();

			// 获得子节点
			List<Node> cList = getRealNodeList(valueNodeList);
			for (Node cNode : cList) {
				Node propertyKeyNode = cNode.getAttributes().getNamedItem(ENTRY_KEY);
				Node propertyValueNode = cNode.getAttributes().getNamedItem(ENTRY_VALUE);

				if (propertyKeyNode != null && propertyValueNode != null) {
					String key = propertyKeyNode.getNodeValue();
					String value = propertyValueNode.getNodeValue();
					properties.put(key, value);
				}

			}

		}

		config.setQuartzProperties(properties);
	}

	/**
	 * MongoDB配置
	 * 
	 * @param root
	 * @param config
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	private void createMongoDBConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException {

		List<Node> mongodbList = this.getRealNodeList(root.getElementsByTagName("mongodb"));
		if (ValidateUtil.isEmpty(mongodbList)) {
			return;
		}

		MongoDBConfig mongoDBConfig = new MongoDBConfig();
		for (int i = 0; i < mongodbList.size(); i++) {
			Node node = mongodbList.get(i);
			if (node.getNodeType() != Node.ELEMENT_NODE) {
				continue;
			}

			NodeList valueNodeList = node.getChildNodes();
			List<Node> nodeList = getRealNodeList(valueNodeList);
			// 反射为数据库配置对象赋值
			reflectCreatBean(nodeList, mongoDBConfig);

		}

		config.setMongoDBConfig(mongoDBConfig);

	}

	/**
	 * 创建Mybatis配置
	 * 
	 * @param root
	 * @param config
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 * @throws XmlConfigException
	 */
	private void createMybatisConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException,
			XmlConfigException {

		List<MyBatisConfig> myBatisConfigList = new ArrayList<>();

		NodeList list = root.getElementsByTagName("environment");
		for (int i = 0; i < list.getLength(); i++) {

			Node node = list.item(i);
			if (node.getNodeType() != Node.ELEMENT_NODE) {
				continue;
			}
			String environmentName = "";
			Node nameNode = node.getAttributes().getNamedItem("name");
			if (nameNode != null) {
				environmentName = nameNode.getNodeValue();
			}
			if (StringUtil.isNull(environmentName)) {
				throw new XmlConfigException("element environment property [name] should not be null");
			}

			NodeList valueNodeList = node.getChildNodes();

			// 获得子节点
			List<Node> nodeList = getRealNodeList(valueNodeList);

			MyBatisConfig myBatisConfig = new MyBatisConfig();

			// 反射为数据库配置对象赋值
			reflectCreatBean(nodeList, myBatisConfig);
			myBatisConfig.setEnvironmentName(environmentName);

			myBatisConfigList.add(myBatisConfig);

		}

		config.setMyBatisConfigList(myBatisConfigList);
	}

	/**
	 * 创建数据源配置
	 * 
	 * @param root
	 * @param config
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 * @throws XmlConfigException
	 */
	private void createDataSourceConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException,
			XmlConfigException {
		NodeList list = root.getElementsByTagName("dataSource");

		Map<String, Map<String, Object>> dataSourceConfigMap = new HashMap<>();

		for (int i = 0; i < list.getLength(); i++) {
			Node node = list.item(i);
			if (node.getNodeType() != Node.ELEMENT_NODE) {
				continue;
			}

			String name = "";
			Node nameNode = node.getAttributes().getNamedItem("name");
			if (nameNode != null) {
				name = nameNode.getNodeValue();
			}

			if (StringUtil.isNull(name)) {
				throw new XmlConfigException("element dataSource property [name] should not be null");
			}

			NodeList valueNodeList = node.getChildNodes();

			// 获得子节点
			List<Node> nodeList = getRealNodeList(valueNodeList);

			// 创建数据源配置Map
			Map<String, Object> dataSourceMap = createDataSourceMap(nodeList);

			dataSourceConfigMap.put(name, dataSourceMap);
		}

		config.setDataSourceConfigMap(dataSourceConfigMap);
	}

	/**
	 * 创建数据源配置Map
	 * 
	 * @param nodeList
	 * @return
	 */
	private Map<String, Object> createDataSourceMap(List<Node> nodeList) {

		Map<String, Object> dataSourceMap = new HashMap<>();

		for (Node valueNode : nodeList) {

			Node propertyKeyNode = valueNode.getAttributes().getNamedItem(ENTRY_KEY);
			Node propertyValueNode = valueNode.getAttributes().getNamedItem(ENTRY_VALUE);

			if (propertyKeyNode != null && propertyValueNode != null) {
				String key = propertyKeyNode.getNodeValue();
				String value = propertyValueNode.getNodeValue();
				dataSourceMap.put(key, value);
			}
		}

		return dataSourceMap;

	}

//	/**
//	 * 创建数据库配置
//	 * 
//	 * @param root
//	 * @param config
//	 * @throws NoSuchFieldException
//	 * @throws IllegalAccessException
//	 */
//	private void createDatabaseConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException {
//		List<DbConfig> dbConfigList = new ArrayList<>();
//
//		NodeList list = root.getElementsByTagName("datasource");
//		for (int i = 0; i < list.getLength(); i++) {
//
//			Node node = list.item(i);
//			if (node.getNodeType() != Node.ELEMENT_NODE) {
//				continue;
//			}
//			DbConfig dbConfig = new DbConfig();
//			dbConfig.setEnvironmentName(node.getAttributes().getNamedItem("Environment").getNodeValue());// EnvironmentName
//
//			NodeList valueNodeList = node.getChildNodes();
//
//			List<Node> nodeList = getRealNodeList(valueNodeList);
//
//			// 反射为数据库配置对象赋值
//			reflectCreatBean(nodeList, dbConfig);
//
//			dbConfigList.add(dbConfig);
//		}
//
//		config.setDbConfigList(dbConfigList);
//
//	}

	/**
	 * 创建webSecurity配置
	 * 
	 * @param root
	 * @param config
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	private void createWebSecurityConfig(Element root, ConfigXmlEntity config) throws NoSuchFieldException, IllegalAccessException {

		WebSecurityConfig webSecurityConfig = null;
		NodeList list = root.getElementsByTagName("secruity");
		for (int i = 0; i < list.getLength(); i++) {

			Node node = list.item(i);
			if (node.getNodeType() != Node.ELEMENT_NODE) {
				continue;
			}

			webSecurityConfig = new WebSecurityConfig();

			NodeList valueNodeList = node.getChildNodes();

			List<Node> nodeList = getRealNodeList(valueNodeList);

			reflectCreatBean(nodeList, webSecurityConfig);

		}

		config.setWebSecurityConfig(webSecurityConfig);

	}

	/**
	 * 获得子节点 去掉空白行
	 * 
	 * @param valueNodeList
	 * @return
	 */
	private List<Node> getRealNodeList(NodeList valueNodeList) {

		if (valueNodeList == null) {
			return new ArrayList<>();
		}

		List<Node> list = new ArrayList<>();

		for (int j = 0; j < valueNodeList.getLength(); j++) {
			Node valueNode = valueNodeList.item(j);
			if (valueNode.getNodeType() == Node.ELEMENT_NODE) {
				list.add(valueNode);
			}
		}

		return list;
	}

	/**
	 * 反射为数据库配置对象赋值
	 * 
	 * @param valueNodeList
	 * @param object
	 * @throws NoSuchFieldException
	 * @throws IllegalAccessException
	 */
	private void reflectCreatBean(List<Node> nodeList, Object object) throws NoSuchFieldException, IllegalAccessException {

		for (Node valueNode : nodeList) {
			Field field = object.getClass().getDeclaredField(valueNode.getAttributes().getNamedItem("key").getNodeValue());
			if (field == null) {// xml节点中的key 在实体类中不存在 则不注入值
				continue;
			}

			// 获取xml中的value值
			if (valueNode.getAttributes().getNamedItem(ENTRY_VALUE) == null) {
				// TODO 此处写法有问题 以后需要考虑改掉
				// 直接写死判断 如果没有value就认为是一个list 然后直接去子节点的value属性
				NodeList valueNodeList = valueNode.getChildNodes();
				List<Node> childNodeList = getRealNodeList(valueNodeList);

				List<String> strList = new ArrayList<>();

				for (Node cNode : childNodeList) {
					String value = cNode.getAttributes().getNamedItem(ENTRY_VALUE).getNodeValue();
					strList.add(value);
				}

				field.setAccessible(true);
				field.set(object, strList);

			} else {
				String value = valueNode.getAttributes().getNamedItem(ENTRY_VALUE).getNodeValue();
				Object resultValue = value;

				if (Integer.TYPE.isAssignableFrom(field.getType())) {
					resultValue = Integer.valueOf(value);
				}

				field.setAccessible(true);
				field.set(object, resultValue);
			}

		}

	}
}
